// Copyright Epic Games, Inc. All Rights Reserved.

#include "Cosmetics/LyraPawnComponent_CharacterParts.h"

#include "Components/SkeletalMeshComponent.h"
#include "Cosmetics/LyraCharacterPartTypes.h"
#include "GameFramework/Character.h"
#include "GameplayTagAssetInterface.h"
#include "Net/UnrealNetwork.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraPawnComponent_CharacterParts)

class FLifetimeProperty;
class UPhysicsAsset;
class USkeletalMesh;
class UWorld;

//////////////////////////////////////////////////////////////////////

/**
 * 获取应用的角色部件条目的调试字符串
 */
FString FLyraAppliedCharacterPartEntry::GetDebugString() const
{
	return FString::Printf(TEXT("(PartClass: %s, Socket: %s, Instance: %s)"), *GetPathNameSafe(Part.PartClass), *Part.SocketName.ToString(), *GetPathNameSafe(SpawnedComponent)); // 格式化返回部件类、插槽和实例的路径名
}

//////////////////////////////////////////////////////////////////////

/**
 * 复制移除前调用
 */
void FLyraCharacterPartList::PreReplicatedRemove(const TArrayView<int32> RemovedIndices, int32 FinalSize)
{
	bool bDestroyedAnyActors = false; // 标记是否销毁了任何Actor
	for (int32 Index : RemovedIndices) // 遍历被移除的索引
	{
		FLyraAppliedCharacterPartEntry& Entry = Entries[Index]; // 获取条目引用
		bDestroyedAnyActors |= DestroyActorForEntry(Entry); // 销毁条目的Actor并更新标记
	}

	if (bDestroyedAnyActors && ensure(OwnerComponent)) // 如果销毁了Actor且拥有组件有效
	{
		OwnerComponent->BroadcastChanged(); // 广播变更
	}
}

/**
 * 复制添加后调用
 */
void FLyraCharacterPartList::PostReplicatedAdd(const TArrayView<int32> AddedIndices, int32 FinalSize)
{
	bool bCreatedAnyActors = false; // 标记是否创建了任何Actor
	for (int32 Index : AddedIndices) // 遍历被添加的索引
	{
		FLyraAppliedCharacterPartEntry& Entry = Entries[Index]; // 获取条目引用
		bCreatedAnyActors |= SpawnActorForEntry(Entry); // 生成条目的Actor并更新标记
	}

	if (bCreatedAnyActors && ensure(OwnerComponent)) // 如果创建了Actor且拥有组件有效
	{
		OwnerComponent->BroadcastChanged(); // 广播变更
	}
}

/**
 * 复制改变后调用
 */
void FLyraCharacterPartList::PostReplicatedChange(const TArrayView<int32> ChangedIndices, int32 FinalSize)
{
	bool bChangedAnyActors = false; // 标记是否改变了任何Actor

	// 我们不支持处理传播更改，只是销毁并重新创建
	for (int32 Index : ChangedIndices) // 遍历被改变的索引
	{
		FLyraAppliedCharacterPartEntry& Entry = Entries[Index]; // 获取条目引用

		bChangedAnyActors |= DestroyActorForEntry(Entry); // 销毁条目的Actor并更新标记
		bChangedAnyActors |= SpawnActorForEntry(Entry); // 重新生成条目的Actor并更新标记
	}

	if (bChangedAnyActors && ensure(OwnerComponent)) // 如果改变了Actor且拥有组件有效
	{
		OwnerComponent->BroadcastChanged(); // 广播变更
	}
}

/**
 * 添加新条目到角色部件列表
 */
FLyraCharacterPartHandle FLyraCharacterPartList::AddEntry(FLyraCharacterPart NewPart)
{
	FLyraCharacterPartHandle Result; // 创建结果句柄
	Result.PartHandle = PartHandleCounter++; // 分配句柄索引并递增计数器

	if (ensure(OwnerComponent && OwnerComponent->GetOwner() && OwnerComponent->GetOwner()->HasAuthority())) // 确保拥有组件、其所有者存在且有权限
	{
		FLyraAppliedCharacterPartEntry& NewEntry = Entries.AddDefaulted_GetRef(); // 在条目列表中添加新条目并获取引用
		NewEntry.Part = NewPart; // 设置部件数据
		NewEntry.PartHandle = Result.PartHandle; // 设置部件句柄
	
		if (SpawnActorForEntry(NewEntry)) // 尝试为条目生成Actor
		{
			OwnerComponent->BroadcastChanged(); // 如果生成了，则广播变更
		}

		MarkItemDirty(NewEntry); // 标记条目为脏以进行复制
	}

	return Result; // 返回句柄
}

/**
 * 从角色部件列表移除指定句柄的条目
 */
void FLyraCharacterPartList::RemoveEntry(FLyraCharacterPartHandle Handle)
{
	for (auto EntryIt = Entries.CreateIterator(); EntryIt; ++EntryIt) // 遍历条目迭代器
	{
		FLyraAppliedCharacterPartEntry& Entry = *EntryIt; // 获取条目引用
		if (Entry.PartHandle == Handle.PartHandle) // 如果句柄匹配
		{
			const bool bDestroyedActor = DestroyActorForEntry(Entry); // 销毁条目的Actor
			EntryIt.RemoveCurrent(); // 从列表中移除当前条目
			MarkArrayDirty(); // 标记数组为脏以进行复制

			if (bDestroyedActor && ensure(OwnerComponent)) // 如果销毁了Actor且拥有组件有效
			{
				OwnerComponent->BroadcastChanged(); // 广播变更
			}

			break; // 跳出循环
		}
	}
}

/**
 * 清除所有条目
 */
void FLyraCharacterPartList::ClearAllEntries(bool bBroadcastChangeDelegate)
{
	bool bDestroyedAnyActors = false; // 标记是否销毁了任何Actor
	for (FLyraAppliedCharacterPartEntry& Entry : Entries) // 遍历所有条目
	{
		bDestroyedAnyActors |= DestroyActorForEntry(Entry); // 销毁条目的Actor并更新标记
	}
	Entries.Reset(); // 重置条目列表
	MarkArrayDirty(); // 标记数组为脏以进行复制

	if (bDestroyedAnyActors && bBroadcastChangeDelegate && ensure(OwnerComponent)) // 如果销毁了Actor、需要广播且拥有组件有效
	{
		OwnerComponent->BroadcastChanged(); // 广播变更
	}
}

/**
 * 收集组合的游戏标签
 */
FGameplayTagContainer FLyraCharacterPartList::CollectCombinedTags() const
{
	FGameplayTagContainer Result; // 创建结果标签容器

	for (const FLyraAppliedCharacterPartEntry& Entry : Entries) // 遍历所有条目
	{
		if (Entry.SpawnedComponent != nullptr) // 如果生成了组件
		{
			if (IGameplayTagAssetInterface* TagInterface = Cast<IGameplayTagAssetInterface>(Entry.SpawnedComponent->GetChildActor())) // 如果子Actor实现了游戏标签资产接口
			{
				TagInterface->GetOwnedGameplayTags(/*inout*/ Result); // 获取拥有的游戏标签并合并到结果中
			}
		}
	}

	return Result; // 返回结果标签容器
}

/**
 * 为条目生成Actor
 */
bool FLyraCharacterPartList::SpawnActorForEntry(FLyraAppliedCharacterPartEntry& Entry)
{
	bool bCreatedAnyActors = false; // 标记是否创建了任何Actor

	if (ensure(OwnerComponent) && !OwnerComponent->IsNetMode(NM_DedicatedServer)) // 确保拥有组件有效且不是专用服务器
	{
		if (Entry.Part.PartClass != nullptr) // 如果部件类有效
		{
			UWorld* World = OwnerComponent->GetWorld(); // 获取世界

			if (USceneComponent* ComponentToAttachTo = OwnerComponent->GetSceneComponentToAttachTo()) // 获取要附加到的场景组件
			{
				const FTransform SpawnTransform = ComponentToAttachTo->GetSocketTransform(Entry.Part.SocketName); // 获取生成变换

				UChildActorComponent* PartComponent = NewObject<UChildActorComponent>(OwnerComponent->GetOwner()); // 创建子Actor组件

				PartComponent->SetupAttachment(ComponentToAttachTo, Entry.Part.SocketName); // 设置附加到指定组件和插槽
				PartComponent->SetChildActorClass(Entry.Part.PartClass); // 设置子Actor类
				PartComponent->RegisterComponent(); // 注册组件

				if (AActor* SpawnedActor = PartComponent->GetChildActor()) // 如果成功生成了子Actor
				{
					switch (Entry.Part.CollisionMode) // 根据碰撞模式处理
					{
					case ECharacterCustomizationCollisionMode::UseCollisionFromCharacterPart:
						// 什么都不做，使用部件自身的碰撞设置
						break;

					case ECharacterCustomizationCollisionMode::NoCollision:
						SpawnedActor->SetActorEnableCollision(false); // 禁用Actor碰撞
						break;
					}

					// 设置直接的Tick依赖，以解决子Actor组件不提供依赖的问题
					if (USceneComponent* SpawnedRootComponent = SpawnedActor->GetRootComponent()) // 如果生成的Actor有根组件
					{
						SpawnedRootComponent->AddTickPrerequisiteComponent(ComponentToAttachTo); // 添加Tick先决条件组件
					}
				}

				Entry.SpawnedComponent = PartComponent; // 记录生成的组件
				bCreatedAnyActors = true; // 标记已创建Actor
			}
		}
	}

	return bCreatedAnyActors; // 返回是否创建了Actor
}

/**
 * 销毁条目的Actor
 */
bool FLyraCharacterPartList::DestroyActorForEntry(FLyraAppliedCharacterPartEntry& Entry)
{
	bool bDestroyedAnyActors = false; // 标记是否销毁了任何Actor

	if (Entry.SpawnedComponent != nullptr) // 如果存在生成的组件
	{
		Entry.SpawnedComponent->DestroyComponent(); // 销毁组件
		Entry.SpawnedComponent = nullptr; // 清空指针
		bDestroyedAnyActors = true; // 标记已销毁Actor
	}

	return bDestroyedAnyActors; // 返回是否销毁了Actor
}

//////////////////////////////////////////////////////////////////////

ULyraPawnComponent_CharacterParts::ULyraPawnComponent_CharacterParts(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	SetIsReplicatedByDefault(true); // 默认设置为复制
}

/**
 * 获取生命周期复制属性
 */
void ULyraPawnComponent_CharacterParts::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 调用父类方法

	DOREPLIFETIME(ThisClass, CharacterPartList); // 复制角色部件列表
}

/**
 * 添加角色部件
 */
FLyraCharacterPartHandle ULyraPawnComponent_CharacterParts::AddCharacterPart(const FLyraCharacterPart& NewPart)
{
	return CharacterPartList.AddEntry(NewPart); // 调用列表的添加条目方法
}

/**
 * 移除角色部件
 */
void ULyraPawnComponent_CharacterParts::RemoveCharacterPart(FLyraCharacterPartHandle Handle)
{
	CharacterPartList.RemoveEntry(Handle); // 调用列表的移除条目方法
}

/**
 * 移除所有角色部件
 */
void ULyraPawnComponent_CharacterParts::RemoveAllCharacterParts()
{
	CharacterPartList.ClearAllEntries(/*bBroadcastChangeDelegate=*/ true); // 调用列表的清除所有条目方法，并广播变更
}

/**
 * 开始播放时调用
 */
void ULyraPawnComponent_CharacterParts::BeginPlay()
{
	Super::BeginPlay(); // 调用父类的BeginPlay
}

/**
 * 结束播放时调用
 */
void ULyraPawnComponent_CharacterParts::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	CharacterPartList.ClearAllEntries(/*bBroadcastChangeDelegate=*/ false); // 清除所有条目，但不广播变更

	Super::EndPlay(EndPlayReason); // 调用父类的EndPlay
}

/**
 * 注册时调用
 */
void ULyraPawnComponent_CharacterParts::OnRegister()
{
	Super::OnRegister(); // 调用父类的OnRegister
	
	if (!IsTemplate()) // 如果不是模板
	{
		CharacterPartList.SetOwnerComponent(this); // 设置列表的拥有组件为此组件
	}
}

/**
 * 获取所有角色部件Actor
 */
TArray<AActor*> ULyraPawnComponent_CharacterParts::GetCharacterPartActors() const
{
	TArray<AActor*> Result; // 创建结果数组
	Result.Reserve(CharacterPartList.Entries.Num()); // 预分配空间

	for (const FLyraAppliedCharacterPartEntry& Entry : CharacterPartList.Entries) // 遍历列表条目
	{
		if (UChildActorComponent* PartComponent = Entry.SpawnedComponent) // 如果存在生成的组件
		{
			if (AActor* SpawnedActor = PartComponent->GetChildActor()) // 如果存在子Actor
			{
				Result.Add(SpawnedActor); // 添加到结果数组
			}
		}
	}

	return Result; // 返回结果数组
}

/**
 * 获取父级骨骼网格体组件
 */
USkeletalMeshComponent* ULyraPawnComponent_CharacterParts::GetParentMeshComponent() const
{
	if (AActor* OwnerActor = GetOwner()) // 获取拥有者Actor
	{
		if (ACharacter* OwningCharacter = Cast<ACharacter>(OwnerActor)) // 如果拥有者是角色
		{
			if (USkeletalMeshComponent* MeshComponent = OwningCharacter->GetMesh()) // 获取角色的网格体组件
			{
				return MeshComponent; // 返回网格体组件
			}
		}
	}

	return nullptr; // 返回空指针
}

/**
 * 获取用于附加的场景组件
 */
USceneComponent* ULyraPawnComponent_CharacterParts::GetSceneComponentToAttachTo() const
{
	if (USkeletalMeshComponent* MeshComponent = GetParentMeshComponent()) // 优先获取父级骨骼网格体组件
	{
		return MeshComponent;
	}
	else if (AActor* OwnerActor = GetOwner()) // 其次使用拥有者的根组件
	{
		return OwnerActor->GetRootComponent();
	}
	else
	{
		return nullptr; // 返回空指针
	}
}

/**
 * 获取组合的标签，可选前缀过滤
 */
FGameplayTagContainer ULyraPawnComponent_CharacterParts::GetCombinedTags(FGameplayTag RequiredPrefix) const
{
	FGameplayTagContainer Result = CharacterPartList.CollectCombinedTags(); // 收集组合标签
	if (RequiredPrefix.IsValid()) // 如果要求前缀有效
	{
		return Result.Filter(FGameplayTagContainer(RequiredPrefix)); // 过滤标签，只保留包含要求前缀的
	}
	else
	{
		return Result; // 直接返回所有组合标签
	}
}

/**
 * 广播变更
 */
void ULyraPawnComponent_CharacterParts::BroadcastChanged()
{
	const bool bReinitPose = true; // 设置重新初始化姿势标志

	// 检查身体类型是否改变
	if (USkeletalMeshComponent* MeshComponent = GetParentMeshComponent()) // 获取父级网格体组件
	{
		// 根据化妆部件标签确定要使用的网格体
		const FGameplayTagContainer MergedTags = GetCombinedTags(FGameplayTag()); // 获取所有组合标签
		USkeletalMesh* DesiredMesh = BodyMeshes.SelectBestBodyStyle(MergedTags); // 选择最佳身体风格网格体

		// 应用所需的网格体（如果网格体未改变，此调用是无操作的）
		MeshComponent->SetSkeletalMesh(DesiredMesh, /*bReinitPose=*/ bReinitPose); // 设置骨骼网格体

		// 如果存在独立于网格体的强制覆盖物理资产，则应用它
		if (UPhysicsAsset* PhysicsAsset = BodyMeshes.ForcedPhysicsAsset) // 如果设置了强制物理资产
		{
			MeshComponent->SetPhysicsAsset(PhysicsAsset, /*bForceReInit=*/ bReinitPose); // 设置物理资产
		}
	}

	// 通知观察者，例如，如果他们需要应用团队颜色等
	OnCharacterPartsChanged.Broadcast(this); // 广播部件改变事件
}